using System;
using System.Collections;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
using System.Reflection;
using System.Runtime.InteropServices;
/*using System.Windows.Forms;*/
using System.Xml;

using SharpVectors.Dom.Svg;

namespace SharpVectors.Renderer.Gdi
{

	/// <summary>
	/// Wraps a Graphics object since it's sealed
	/// </summary>
	public class GraphicsWrapper : IDisposable 
	{
    #region Private Fields
		private bool _isStatic;
		private Graphics _graphics;
		private Graphics _idMapGraphics;
		private Bitmap _idMapImage;
    #endregion

    #region Constructors
		private GraphicsWrapper(Image image, bool isStatic)
		{
      this._isStatic = isStatic;
			if(!IsStatic)
			{
				_idMapImage = new Bitmap(image.Width, image.Height);
				_idMapGraphics = Graphics.FromImage(_idMapImage);
        _idMapGraphics.InterpolationMode = InterpolationMode.NearestNeighbor;
        _idMapGraphics.SmoothingMode = SmoothingMode.None;
        _idMapGraphics.CompositingQuality = CompositingQuality.Invalid;
			}
			_graphics = Graphics.FromImage(image);
		}

    private GraphicsWrapper(IntPtr hdc, bool isStatic)
    {
      this._isStatic = isStatic;
      if(!IsStatic)
      {
        // This will get resized when the actual size is known
        _idMapImage = new Bitmap(0, 0);
        _idMapGraphics = Graphics.FromImage(_idMapImage);
        _idMapGraphics.InterpolationMode = InterpolationMode.NearestNeighbor;
        _idMapGraphics.SmoothingMode = SmoothingMode.None;
        _idMapGraphics.CompositingQuality = CompositingQuality.Invalid;
      }
      _graphics = Graphics.FromHdc(hdc);
    }
    #endregion

		public static GraphicsWrapper FromImage(Image image, bool isStatic)
		{
			return new GraphicsWrapper(image, isStatic);
		}

    public static GraphicsWrapper FromHdc(IntPtr hdc, bool isStatic)
    {
      return new GraphicsWrapper(hdc, isStatic);
    }

    #region Properties
		public bool IsStatic
		{
			get{return _isStatic;}
			set{
				_isStatic = value;
        _idMapGraphics.Dispose();
				_idMapGraphics = null;
			}
		}

		public Graphics Graphics
		{
			get{return _graphics;}
			set{_graphics = value;}
		}

		public Graphics IdMapGraphics
		{
			get{return _graphics;}
		}

		public Bitmap IdMapRaster
		{
			get{return _idMapImage;}
		}
    #endregion

		#region Graphics members
		public void Clear(Color color)
		{
			_graphics.Clear(color);
			if(_idMapGraphics != null) _idMapGraphics.Clear(Color.Empty);
		}

		public void Dispose()
		{
			_graphics.Dispose();
			if(_idMapGraphics != null) _idMapGraphics.Dispose();
		}

		public GraphicsContainerWrapper BeginContainer()
		{
      GraphicsContainerWrapper container = new GraphicsContainerWrapper();
			if(_idMapGraphics != null) container.idmapGraphicsContainer = _idMapGraphics.BeginContainer();
			container.mainGraphicsContainer = _graphics.BeginContainer();
      return container;
		}

		public void EndContainer(GraphicsContainerWrapper container)
		{
			if(_idMapGraphics != null) _idMapGraphics.EndContainer(container.idmapGraphicsContainer);
			_graphics.EndContainer(container.mainGraphicsContainer);
		}

		public SmoothingMode SmoothingMode
		{
			get{return _graphics.SmoothingMode;}
			set{_graphics.SmoothingMode = value;}
		}

		public Matrix Transform
		{
			get{return _graphics.Transform;}
			set
			{
				if(_idMapGraphics != null) _idMapGraphics.Transform = value;
				_graphics.Transform = value;
			}
		}

		public void SetClip(GraphicsPath path)
		{
			_graphics.SetClip(path);
		}

		public void SetClip(RectangleF rect)
		{
			if(_idMapGraphics != null) _idMapGraphics.SetClip(rect);
			_graphics.SetClip(rect);
		}

		public void SetClip(Region region, CombineMode combineMode)
		{
			if(_idMapGraphics != null) _idMapGraphics.SetClip(region, combineMode);
			_graphics.SetClip(region, combineMode);
		}

		public void TranslateClip(float x, float y)
		{
			if(_idMapGraphics != null) _idMapGraphics.TranslateClip(x, y);
			_graphics.TranslateClip(x, y);
		}

		public void ResetClip()
		{
			if(_idMapGraphics != null) _idMapGraphics.ResetClip();
			_graphics.ResetClip();
		}

		public void FillPath(GraphicsNode grNode, Brush brush, GraphicsPath path )
		{
			if(_idMapGraphics != null)
			{
				Brush idBrush = new SolidBrush(grNode.UniqueColor);
				if(grNode.Element is SvgTextContentElement)
				{
					_idMapGraphics.FillRectangle(idBrush, path.GetBounds());
				}
				else
				{
					_idMapGraphics.FillPath(idBrush, path);
				}
			}
			_graphics.FillPath(brush, path);
		}

		public void DrawPath(GraphicsNode grNode, Pen pen, GraphicsPath path)
		{
			if(_idMapGraphics != null)
			{
				Pen idPen = new Pen(grNode.UniqueColor, pen.Width);
				_idMapGraphics.DrawPath(idPen, path);
			}
			_graphics.DrawPath(pen, path);
		}

		public void TranslateTransform(float dx, float dy)
		{
			if(_idMapGraphics != null) _idMapGraphics.TranslateTransform(dx, dy);
			_graphics.TranslateTransform(dx, dy);
		}

		public void ScaleTransform(float sx, float sy)
		{
			if(_idMapGraphics != null) _idMapGraphics.ScaleTransform(sx, sy);
			_graphics.ScaleTransform(sx, sy);
		}

		public void RotateTransform(float angle)
		{
			if(_idMapGraphics != null) _idMapGraphics.RotateTransform(angle);
			_graphics.RotateTransform(angle);
		}

    public void DrawImage(GraphicsNode grNode, Image image, Rectangle destRect, float srcX, float srcY, float srcWidth, float srcHeight, GraphicsUnit graphicsUnit, ImageAttributes imageAttributes)
		{
      if(_idMapGraphics != null)
      {
        // This handles pointer-events for visibleFill visibleStroke and visible
        /*Brush idBrush = new SolidBrush(grNode.UniqueColor);
        GraphicsPath gp = new GraphicsPath();
        gp.AddRectangle(destRect);
        _idMapGraphics.FillPath(idBrush, gp);*/
        Color unique = grNode.UniqueColor;
        float r = (float)unique.R / 255;
        float g = (float)unique.G / 255;
        float b = (float)unique.B / 255;
        ColorMatrix colorMatrix = new ColorMatrix(        
          new float[][] { new float[] {0f, 0f, 0f, 0f, 0f},
                          new float[] {0f, 0f, 0f, 0f, 0f},
                          new float[] {0f, 0f, 0f, 0f, 0f},
                          new float[] {0f, 0f, 0f, 1f, 0f},
                          new float[] {r,  g,  b,  0f, 1f} });    
        ImageAttributes ia = new ImageAttributes();
        ia.SetColorMatrix(colorMatrix,ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
        _idMapGraphics.DrawImage(image, destRect, srcX, srcY, srcWidth, srcHeight, graphicsUnit, ia);
      }
      _graphics.DrawImage(image, destRect, srcX, srcY, srcWidth, srcHeight, graphicsUnit, imageAttributes);
		}
		#endregion

	}

  /// <summary>
  /// Wraps a GraphicsContainer because it is sealed.
  /// This is a helper for GraphicsWrapper so that it can save
  /// multiple container states. It holds the containers
  /// for both the idMapGraphics and the main graphics
  /// being rendered in the GraphicsWrapper.
  /// </summary>
  public struct GraphicsContainerWrapper {
    internal GraphicsContainer idmapGraphicsContainer;
    internal GraphicsContainer mainGraphicsContainer;
  }

}
